home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’87 / Source ƒ.sit / Source ƒ / C ƒ / TRANS-LSC / TransDisplay.c < prev    next >
Encoding:
Text File  |  1986-11-12  |  23.9 KB  |  1,105 lines  |  [TEXT/KAHL]

  1. /*
  2.     TransDisplay version 1.0 - TransSkel plug-in module supporting
  3.     an arbitrary number of generic display windows with memory.
  4.  
  5.     TransSkel and TransDisplay are public domain, and are written by:
  6.  
  7.             Paul DuBois
  8.             Wisconsin Regional Primate Research Center
  9.             1220 Capital Court
  10.             Madison WI  53706  USA
  11.  
  12.     UUCP:    {allegra,ihnp4,seismo}!uwvax!uwmacc!dubois
  13.     ARPA:    dubois@unix.macc.wisc.edu
  14.             dubois@rhesus.primate.wisc.edu
  15.  
  16.     This version of TransDisplay written for LightspeedC.  LightspeedC
  17.     is a trademark of:
  18.             THINK Technologies, Inc
  19.             420 Bedford Street  Suite 350
  20.             Lexington, MA  02173  USA
  21.  
  22.   History
  23.   08/25/86    Genesis.  Beta version.
  24.   09/15/86    Changed to allow arbitrary number of windows.  Changed
  25.              version number to 1.0.
  26. */
  27.  
  28.  
  29. /*
  30.     The following symbol controls the compile mode.  If it is #define'd,
  31.     TransDisplay allows only a single display window, and generates
  32.     less code.  If it is #undef'ed, TransDisplay allows an arbitrary
  33.     number of display windows, but generates more code.
  34. */
  35.  
  36. # undef    singleDisplay
  37.  
  38. # include    <ControlMgr.h>    /* includes WindowMgr.h, QuickDraw.h, MacTypes.h */
  39. # include    <TextEdit.h>
  40. # include    "TransDisplay.h"
  41.  
  42.  
  43. /*
  44.     Display window types, constants, variables.
  45. */
  46.  
  47.  
  48. # define    monaco        4
  49.  
  50.  
  51. /*
  52.     Default values for display window characteristics
  53. */
  54.  
  55. static int        d_font = monaco;        /* default font              */
  56. static int        d_size = 9;                /* default pointsize         */
  57. static int        d_wrap = 0;                /* default word wrap (on)    */
  58. static int        d_just = teJustLeft;    /* default justification     */
  59. static long        d_maxText = 30000L;        /* default max text allowed  */
  60. static long        d_flushAmt = 25000L;    /* default autoflush amount  */
  61. static ProcPtr    d_activate = nil;        /* default notification proc */
  62.  
  63.  
  64. /*
  65.     Lowest allowable values for autoflush characteristics
  66. */
  67.  
  68. # define    d_loMaxText        (100L)
  69. # define    d_loFlushAmt    (100L)
  70.  
  71.  
  72. # ifndef    singleDisplay
  73.  
  74. /*
  75.     New(TypeName) returns handle to new object, for any TypeName.
  76.     If there is insufficient memory, the result is nil.
  77. */
  78.  
  79. # define    New(x)    (x **) NewHandle ((Size) sizeof (x))
  80.  
  81.  
  82. /*
  83.     dwList points to a list of structures describing the known display
  84.     windows.
  85.  
  86.     curDispWind is the current output window.
  87.     If curDispWind = nil, output is currently turned off.
  88. */
  89.  
  90.  
  91. typedef struct DisplayInfo
  92. {
  93.     WindowPtr            dWind;            /* display window         */
  94.     TEHandle            dTE;            /* window text            */
  95.     ControlHandle        dScroll;        /* window scroll bar      */
  96.     ProcPtr                dActivate;        /* notification procedure */
  97.     long                dMaxText;        /* max text length        */
  98.     long                dFlushAmt;        /* amount to autoflush    */
  99.     struct DisplayInfo    **dNext;        /* next window structure  */
  100. } DisplayInfo, *DIPtr, **DIHandle;
  101.  
  102.  
  103. static DIHandle        dwList = nil;
  104.  
  105. # endif
  106.  
  107. /*
  108.     Variables pertaining to the display window being operated on
  109.     (updated, resized, etc.).  This window is not necessarily the
  110.     same as curDispWind!  These variables are synced to the window
  111.     with SyncGlobals.
  112. */
  113.  
  114. # ifndef    singleDisplay
  115. static DIHandle            dispInfo;        /* info structure         */
  116. # endif
  117.  
  118. static WindowPtr        dispWind = nil;    /* the window             */
  119. static TEHandle            dispTE;            /* window text            */
  120. static ControlHandle    dispScroll;        /* the scroll bar         */
  121. static ProcPtr            dActivate;        /* notification procedure */
  122. static long                dMaxText;        /* max text allowed       */
  123. static long                dFlushAmt;        /* amount to flush        */
  124.  
  125.  
  126. /*
  127.     curDispWind is the current output window.
  128.     If curDispWind = nil, output is turned off.
  129. */
  130.  
  131. static WindowPtr    curDispWind = nil;
  132.  
  133.  
  134. /* -------------------------------------------------------------------- */
  135. /*                Miscellaneous Internal (private) Routines                */
  136. /* -------------------------------------------------------------------- */
  137.  
  138.  
  139. /*
  140.     Draw grow box of dispWind in lower right hand corner
  141. */
  142.  
  143.  
  144. static DrawGrowBox ()
  145. {
  146. register RgnHandle    oldClip;
  147. Rect                r;
  148.  
  149.     r = dispWind->portRect;
  150.     r.left = r.right - 15;        /* draw only in corner */
  151.     r.top = r.bottom - 15;
  152.     oldClip = NewRgn ();
  153.     GetClip (oldClip);
  154.     ClipRect (&r);
  155.     DrawGrowIcon (dispWind);
  156.     SetClip (oldClip);
  157.     DisposeRgn (oldClip);
  158. }
  159.  
  160.  
  161.  
  162. /* -------------------------------------------------------------------- */
  163. /*            Lowest-level Internal (Private) Display Window Routines        */
  164. /* -------------------------------------------------------------------- */
  165.  
  166.  
  167. # ifndef    singleDisplay
  168.  
  169. /*
  170.     Get display window info associated with window.
  171.     Return nil if window isn't a known display window.
  172. */
  173.  
  174. static DIHandle GetDInfo (theWind)
  175. WindowPtr    theWind;
  176. {
  177. register DIHandle    h;
  178.  
  179.     for (h = dwList; h != nil; h = (**h).dNext)
  180.     {
  181.         if ((**h).dWind == theWind)
  182.             return (h);
  183.     }
  184.     return (nil);
  185. }
  186.  
  187. # endif
  188.  
  189. # ifdef    singleDisplay
  190. # define    SyncGlobals(x)    ;    /* make it a nop */
  191. # else
  192.  
  193. /*
  194.     Synchronize globals to a display window.  theWind must be a legal
  195.     display window, with one exception:  if theWind is nil, the
  196.     variables are synced to the current port.  That is safe (and
  197.     correct) because:
  198.     (i)     nil is only passed by display window handler procedures,
  199.          which are only called by TransSkel for display window
  200.          events.
  201.     (ii) TransSkel always sets the port to the window before
  202.          calling the handler proc.
  203.     Hence, use of the current port under these circumstances
  204.     always produces a legal display window.
  205.     
  206.     SyncGlobals is not used in single display mode, because the
  207.     globals are all set by SetupDWindow and do not change thereafter.
  208. */
  209.  
  210. static SyncGlobals (theWind)
  211. WindowPtr    theWind;
  212. {
  213. register DIPtr    dp;
  214.  
  215.     if (theWind == nil)                    /* use current window */
  216.         GetPort (&theWind);
  217.  
  218.     dispWind = theWind;
  219.     dispInfo = GetDInfo (dispWind);
  220.     dp = *dispInfo;
  221.     dispScroll = (*dp).dScroll;
  222.     dispTE = (*dp).dTE;
  223.     dActivate = (*dp).dActivate;
  224.     dMaxText = (*dp).dMaxText;
  225.     dFlushAmt = (*dp).dFlushAmt;
  226. }
  227.  
  228. # endif
  229.  
  230.  
  231. /*
  232.     Calculate the dimensions of the editing rectangle for
  233.     dispWind (which must be set properly and is assumed to be
  234.     the current port).  (The viewRect and destRect are the
  235.     same size.)  Assumes the port, text font and text size are all
  236.     set properly.  The viewRect is sized so that an integral
  237.     number of lines can be displayed in it, i.e., so that a
  238.     partial line never shows at the bottom.
  239. */
  240.  
  241. static CalcEditRect (r)
  242. Rect        *r;
  243. {
  244. FontInfo        f;
  245. register int    lineHeight;
  246.  
  247.     GetFontInfo (&f);
  248.     lineHeight = f.ascent + f.descent + f.leading;
  249.     *r = dispWind->portRect;
  250.     r->left += 4;
  251.     r->right -= 17;            /* leave room for scroll bar + 2 */
  252.     r->top += 2;
  253.     r->bottom = r->top + ((r->bottom - r->top - 2) / lineHeight) * lineHeight;
  254. }
  255.  
  256.  
  257. /*
  258.     Calculate the dimensions of the scroll bar rectangle for the
  259.     window.  Make sure that the edges overlap the window frame and
  260.     the grow box.
  261. */
  262.  
  263. static CalcScrollRect (r)
  264. Rect        *r;
  265. {
  266.     *r = dispWind->portRect;
  267.     ++r->right;
  268.     --r->top;
  269.     r->left = r->right - 16;
  270.     r->bottom -= 14;
  271. }
  272.  
  273.  
  274. /*
  275.     Calculate the number of lines currently scrolled off
  276.     the top.
  277. */
  278.  
  279. static LinesOffTop ()
  280. {
  281. register TEPtr    ePtr;
  282.  
  283.     ePtr = *dispTE;
  284.     return (((*ePtr).viewRect.top - (*ePtr).destRect.top)
  285.                 / (*ePtr).lineHeight);
  286. }
  287.  
  288.  
  289. /*
  290.     Highlight the scroll bar properly.  This means that it's not
  291.     made active if the window itself isn't active, even if
  292.     there's enough text to fill the window.
  293. */
  294.  
  295. static HiliteScroll ()
  296. {
  297.     HiliteControl (dispScroll, dispWind == FrontWindow () &&
  298.                                 GetCtlMax (dispScroll) > 0 ? 0 : 255);
  299. }
  300.  
  301.  
  302. /*
  303.     Scroll to the correct position.  lDelta is the
  304.     amount to CHANGE the current scroll setting by.
  305.     Positive scrolls the text up, negative down.
  306. */
  307.  
  308. static ScrollText (lDelta)
  309. int        lDelta;
  310. {
  311. register int    lHeight;
  312. register int    newLine;
  313. register int    topLine;
  314.  
  315.     lHeight = (**dispTE).lineHeight;
  316.     topLine = LinesOffTop ();
  317.     newLine = topLine + lDelta;
  318.     if (newLine < 0)
  319.         newLine = 0;
  320.     if (newLine > GetCtlMax (dispScroll))
  321.         newLine = GetCtlMax (dispScroll);
  322.     SetCtlValue (dispScroll, newLine);
  323.     TEScroll (0, (topLine - newLine ) * lHeight, dispTE);
  324. }
  325.  
  326.  
  327. /*
  328.     Filter proc for tracking mousedown in scroll bar.  The code for
  329.     the part originally hit is stored in the control's reference
  330.     value by Mouse () before calling this.
  331.  
  332.     Scroll by one line if the mouse is in an arrow.  Scroll by a half
  333.     window's worth of lines if the mouse is in a page region.
  334. */
  335.  
  336. static pascal void TrackScroll (theScroll, partCode)
  337. ControlHandle    theScroll;
  338. int                partCode;
  339. {
  340. register int    lDelta;
  341. register int    halfPage;
  342.  
  343.     if (partCode == GetCRefCon (theScroll))    /* still in same part? */
  344.     {
  345.         halfPage = (((**dispTE).viewRect.bottom - (**dispTE).viewRect.top)
  346.                         / (**dispTE).lineHeight) / 2;
  347.         if (halfPage == 0)
  348.             ++halfPage;
  349.         switch (partCode)
  350.         {
  351.             case inUpButton: lDelta = -1; break;
  352.             case inDownButton: lDelta = 1; break;
  353.             case inPageUp: lDelta = -halfPage; break;
  354.             case inPageDown: lDelta = halfPage; break;
  355.         }
  356.         ScrollText (lDelta);
  357.     }
  358. }
  359.  
  360.  
  361. /*
  362.     Adjust the text in the text record and the scroll bar.  This is
  363.     called for major catastrophes, such as resizing the window, or
  364.     changing the word wrap style.  It makes sure the view and
  365.     destination rectangles are sized properly, and that the bottom
  366.     line of text never scrolls up past the bottom line of the
  367.     window, if there's enough to fill the window, and that the
  368.     scroll bar max and current values are set properly.
  369.  
  370.     Resizing the dest rect just means resetting the right edge
  371.     (the top is NOT reset), since text might be scrolled off the
  372.     top (i.e., destRect.top != 0).
  373. */
  374.  
  375. static OverhaulDisplay ()
  376. {
  377. Rect            r;
  378. register int    nLines;            /* number of lines in TERec */
  379. register int    visLines;        /* number of lines displayable in window */
  380. register int    topLines;        /* number of lines currently scrolled off top */
  381. register int    scrollLines;    /* number of lines to scroll down */
  382. register int    lHeight;
  383.  
  384.     CalcEditRect (&r);
  385.     (**dispTE).destRect.right = r.right;
  386.     (**dispTE).viewRect = r;
  387.     TECalText (dispTE);        /* recalc line starts */
  388.     /*r = (**dispTE).viewRect;*/    /* ?? */
  389.     lHeight = (**dispTE).lineHeight;
  390.     nLines = (**dispTE).nLines;
  391.     visLines = (r.bottom - r.top) / lHeight;
  392.     topLines = LinesOffTop ();
  393.  
  394. /*
  395.     If the text doesn't fill the window (visLines > nLines - topLines),
  396.     pull the text down if possible (if topLines > 0).  Make sure not
  397.     to try to scroll down by more lines than are hidden off the top.
  398. */
  399.     scrollLines = visLines - (nLines - topLines);
  400.     if (scrollLines > 0 && topLines > 0)
  401.     {
  402.         if (scrollLines > topLines)
  403.             scrollLines = topLines;
  404.         TEScroll (0, scrollLines * lHeight, dispTE);
  405.         topLines -= scrollLines;
  406.     }
  407.     TEUpdate (&r, dispTE);
  408.  
  409.     SetCtlMax (dispScroll, nLines - visLines < 0 ? 0 : nLines - visLines);
  410.     SetCtlValue (dispScroll, topLines);
  411.     HiliteScroll ();
  412. }
  413.  
  414.  
  415. /* ---------------------------------------------------------------- */
  416. /*                        Window Handler Routines                        */
  417. /* ---------------------------------------------------------------- */
  418.  
  419.  
  420. /*
  421.     When the window comes active, highlight the scroll bar appropriately.
  422.     When the window is deactivated, un-highlight the scroll bar.
  423.     Redraw the grow box.
  424.  
  425.     Notify the host as appropriate.
  426.  
  427.     Note that clicking close box hides the window, which generates a
  428.     deactivate event, so there is no need for a close notifier.
  429. */
  430.  
  431. static Activate (isActive)
  432. Boolean    isActive;
  433. {
  434.     SyncGlobals (nil);                /* sync to current port */
  435.     DrawGrowBox ();
  436.     HiliteScroll ();
  437.  
  438.     if (dActivate != nil)
  439.         (*dActivate) (isActive);
  440. }
  441.  
  442.  
  443. /*
  444.     Update window.  The update event might be in response to a
  445.     window resizing.  If so, move and resize the scroll bar,
  446.     and recalculate the text display.
  447.  
  448.     The ValidRect call is done because the HideControl adds the
  449.     control bounds box to the update region - which would generate
  450.     another update event!  Since everything is redrawn below anyway,
  451.     the ValidRect is used to cancel the update.
  452. */
  453.  
  454. static Update (resized)
  455. Boolean    resized;
  456. {
  457. Rect    r;
  458.  
  459.     SyncGlobals (nil);                    /* sync to current port */
  460.     r = dispWind->portRect;
  461.     EraseRect (&r);
  462.     if (resized)
  463.     {
  464.         HideControl (dispScroll);
  465.         r = (**dispScroll).contrlRect;
  466.         ValidRect (&r);
  467.         CalcScrollRect (&r);
  468.         SizeControl (dispScroll, 16, r.bottom - r.top);
  469.         MoveControl (dispScroll, r.left, r.top);
  470.         OverhaulDisplay ();
  471.         ShowControl (dispScroll);
  472.     }
  473.     else
  474.     {
  475.         r = (**dispTE).viewRect;
  476.         TEUpdate (&r, dispTE);        /* redraw text display */
  477.     }
  478.  
  479.     DrawGrowBox ();
  480.     DrawControls (dispWind);    /* redraw scroll bar */
  481. }
  482.  
  483.  
  484. /*
  485.     Handle mouse clicks in window
  486. */
  487.  
  488. static Mouse (thePt, t, mods)
  489. Point    thePt;
  490. long    t;
  491. int        mods;
  492. {
  493. register int    thePart;
  494. register int    oldCtlValue;
  495.  
  496.     SyncGlobals (nil);                /* sync to current port */
  497.  
  498.     if ((thePart = TestControl (dispScroll, thePt)) == inThumb)
  499.     {
  500.         oldCtlValue = GetCtlValue (dispScroll);
  501.         if (TrackControl (dispScroll, thePt, nil) == inThumb)
  502.             ScrollText (GetCtlValue (dispScroll) - oldCtlValue);
  503.     }
  504.     else if (thePart != 0)
  505.     {
  506.         SetCRefCon (dispScroll, (long) thePart);
  507.         (void) TrackControl (dispScroll, thePt, &TrackScroll);
  508.     }
  509. }
  510.  
  511.  
  512.  
  513. /*
  514.     Remove the display window from the list, and dispose of it.
  515.     Since the clobber procedure is never called except for real display
  516.     windows, and since the list must therefore be non-empty, it is
  517.     not necessary to check the legality of the window or that the
  518.     window's in the list.
  519.  
  520.     Must do SetDWindow (nil) to turn output off, if the window being
  521.     clobbered is the current output window.
  522. */
  523.  
  524. static Clobber ()
  525. {
  526. # ifndef    singleDisplay
  527. register DIHandle    h, h2;
  528. # endif
  529.  
  530.     SyncGlobals (nil);                    /* sync to current port */
  531.  
  532.     if (dispWind == curDispWind)
  533.         SetDWindow (nil);
  534.  
  535. # ifndef    singleDisplay
  536.  
  537.     if ((**dwList).dWind == dispWind)    /* is it the first window in list? */
  538.     {
  539.         h2 = dwList;
  540.         dwList = (**dwList).dNext;
  541.     }
  542.     else
  543.     {
  544.         for (h = dwList; h != nil; h = h2)
  545.         {
  546.             h2 = (**h).dNext;
  547.             if ((**h2).dWind == dispWind)    /* found it */
  548.             {
  549.                 (**h).dNext = (**h2).dNext;
  550.                 break;
  551.             }
  552.         }
  553.     }
  554.     DisposHandle (h2);        /* get rid of information structure */
  555.  
  556. # endif
  557.  
  558.     TEDispose (dispTE);            /* toss text record */
  559.     DisposeWindow (dispWind);    /* toss window and scroll bar */
  560.     dispWind = nil;
  561. }
  562.  
  563.  
  564. /* ---------------------------------------------------------------- */
  565. /*                            Control Routines                        */
  566. /* ---------------------------------------------------------------- */
  567.  
  568.  
  569. /*
  570.     Test whether a window is a legal display window or not
  571. */
  572.  
  573. Boolean IsDWindow (theWind)
  574. WindowPtr    theWind;
  575. {
  576.  
  577. # ifdef    singleDisplay
  578.     return (theWind == dispWind && dispWind != nil);
  579. # else
  580.     return (GetDInfo (theWind) != nil);
  581. # endif
  582. }
  583.  
  584.  
  585. /*
  586.     Return handle to display window's text record
  587. */
  588.  
  589. TEHandle GetDWindowTE (theWind)
  590. WindowPtr    theWind;
  591. {
  592.  
  593. # ifndef    singleDisplay
  594. register DIHandle    dInfo;
  595.     return (GetDInfo (theWind) == nil ? nil : (**dInfo).dTE);
  596. # else
  597.     return (IsDWindow (theWind) ? dispTE : nil);
  598. # endif
  599. }
  600.  
  601.  
  602. /*
  603.     Change the text display characteristics of a display window
  604.     and redisplay it.  As a side effect, this always scrolls to the
  605.     home position.
  606. */
  607.  
  608. SetDWindowStyle (theWind, font, size, wrap, just)
  609. WindowPtr    theWind;
  610. int            font;
  611. int            size;
  612. int            wrap;
  613. int            just;
  614. {
  615. GrafPtr                savePort;
  616. FontInfo            f;
  617. register TEHandle    te;
  618. Rect                r;
  619.  
  620.     if (theWind == nil)            /* reset window creation defaults */
  621.     {
  622.         d_font = font;
  623.         d_size = size;
  624.         d_wrap = wrap;
  625.         d_just = just;
  626.         return;
  627.     }
  628.  
  629.     if (IsDWindow (theWind))
  630.     {
  631.         GetPort (&savePort);
  632.         SyncGlobals (theWind);
  633.         SetPort (dispWind);
  634.         te = dispTE;
  635.         r = (**te).viewRect;
  636.         EraseRect (&r);
  637.         r = (**te).destRect;    /* scroll home without redrawing */
  638.         OffsetRect (&r, 0, 2 - r.top);
  639.         (**te).destRect = r;
  640.  
  641.         (**te).crOnly = wrap;    /* set word wrap */
  642.         TESetJust (just, te);    /* set justification */
  643.  
  644.         TextFont (font);         /* set the font and point size */
  645.         TextSize (size);        /* of text record (this is the */
  646.         GetFontInfo (&f);        /* hard part) */
  647.         (**te).lineHeight = f.ascent + f.descent + f.leading;
  648.         (**te).fontAscent = f.ascent;
  649.         (**te).txFont = font;
  650.         (**te).txSize = size;
  651.  
  652.         OverhaulDisplay ();
  653.         SetPort (savePort);
  654.     }
  655. }
  656.  
  657.  
  658. /*
  659.     Scroll the text in the window so that line lineNum is at the top.
  660.     First line is line zero.
  661. */
  662.  
  663. SetDWindowPos (theWind, lineNum)
  664. WindowPtr    theWind;
  665. int            lineNum;
  666. {
  667. GrafPtr        savePort;
  668.  
  669.     if (IsDWindow (theWind))
  670.     {
  671.         GetPort (&savePort);
  672.         SyncGlobals (theWind);
  673.         SetPort (dispWind);
  674.         ScrollText (lineNum - GetCtlValue (dispScroll));
  675.         SetPort (savePort);
  676.     }
  677. }
  678.  
  679.  
  680. /*
  681.     Set display window activate notification procedure.
  682.     Pass nil to disable it.
  683. */
  684.  
  685. SetDWindowNotify (theWind, p)
  686. WindowPtr    theWind;
  687. ProcPtr        p;
  688. {
  689. # ifndef    singleDisplay
  690. register DIHandle    dInfo;
  691. # endif
  692.  
  693.     if (theWind == nil)            /* reset window creation default */
  694.     {
  695.         d_activate = p;
  696.         return;
  697.     }
  698.  
  699. # ifdef    singleDisplay
  700.  
  701.     if (IsDWindow (theWind))
  702.         dActivate = p;
  703.  
  704. # else
  705.  
  706.     if ((dInfo = GetDInfo (theWind)) != nil)
  707.     {
  708.         (**dInfo).dActivate = p;
  709.     }
  710.  
  711. # endif
  712. }
  713.  
  714.  
  715. /*
  716.     Set display window autoflush characteristics
  717. */
  718.  
  719. SetDWindowFlush (theWind, maxText, flushAmt)
  720. WindowPtr    theWind;
  721. long        maxText;
  722. long        flushAmt;
  723. {
  724. # ifndef    singleDisplay
  725. register DIHandle    dInfo;
  726. # endif
  727.  
  728.     if (maxText > 32767L)
  729.         maxText = 32767L;
  730.     if (maxText < d_loMaxText)
  731.         maxText = d_loMaxText;
  732.     if (flushAmt < d_loFlushAmt)
  733.         flushAmt = d_loFlushAmt;
  734.  
  735.     if (theWind == nil)            /* reset window creation defaults */
  736.     {
  737.         d_maxText = maxText;
  738.         d_flushAmt = flushAmt;
  739.         return;
  740.     }
  741.  
  742. # ifdef    singleDisplay
  743.  
  744.     if (IsDWindow (theWind))
  745.     {
  746.  
  747.         dMaxText = maxText;
  748.         dFlushAmt = flushAmt;
  749.     }
  750.  
  751. # else
  752.  
  753.     if ((dInfo = GetDInfo (theWind)) != nil)
  754.     {
  755.         (**dInfo).dMaxText = maxText;
  756.         (**dInfo).dFlushAmt = flushAmt;
  757.     }
  758.  
  759. # endif
  760. }
  761.  
  762.  
  763. /*
  764.     Set which display window is to be used for output.  If theWind
  765.     is nil, output is turned off.  If theWind is not a legal display
  766.     window, nothing is done.
  767. */
  768.  
  769. SetDWindow (theWind)
  770. WindowPtr    theWind;
  771. {
  772.     if (theWind == nil || IsDWindow (theWind))
  773.     {
  774.         curDispWind = theWind;
  775.     }
  776. }
  777.  
  778.  
  779. /*
  780.     Get the WindowPtr of the current output display window.  If
  781.     output is turned off, this will be nil.
  782. */
  783.  
  784. GetDWindow (theWind)
  785. WindowPtr    *theWind;
  786. {
  787.     *theWind = curDispWind;
  788. }
  789.  
  790.  
  791. /*
  792.     Flush text from the window and readjust the display.
  793. */
  794.  
  795. FlushDWindow (theWind, byteCount)
  796. WindowPtr    theWind;
  797. long        byteCount;
  798. {
  799.     if (IsDWindow (theWind))
  800.     {
  801.         SyncGlobals (theWind);
  802.         TESetSelect (0L, byteCount, dispTE);    /* select text */
  803.         TEDelete (dispTE);                        /* clobber it */
  804.         OverhaulDisplay ();
  805.     }
  806. }
  807.  
  808.  
  809. /*
  810.     Create and initialize a display window and the associated data
  811.     structures, and return the window pointer.  Install window in
  812.     list of display windows.
  813. */
  814.  
  815. static SetupDWindow ()
  816. {
  817. Rect                r;
  818. GrafPtr                savePort;
  819.  
  820. # ifndef    singleDisplay
  821. register DIHandle    dInfo;
  822. # endif
  823.  
  824.  
  825.     GetPort (&savePort);
  826.     SkelWindow (dispWind,    /* the window */
  827.                 Mouse,        /* mouse click handler */
  828.                 nil,        /* key clicks are ignored */
  829.                 Update,        /* window updating procedure */
  830.                 Activate,    /* window activate/deactivate procedure */
  831.                 nil,        /* TransSkel hides window if no close proc */
  832.                             /* (generates deactivate event) */
  833.                 Clobber,    /* window disposal procedure */
  834.                 nil,        /* no idle proc */
  835.                 false);        /* irrelevant since no idle proc */
  836.  
  837. /*
  838.     Build the scroll bar.  Make sure the borders overlap the
  839.     window frame and the frame of the grow box.
  840. */
  841.  
  842.     CalcScrollRect (&r);
  843.     dispScroll = NewControl (dispWind, &r, "\p", true, 0, 0, 0,
  844.                                 scrollBarProc, 0L);
  845.  
  846. /*
  847.     Create the TE record used for text display.  Use defaults for
  848.     display characteristics.  Setting window style overhauls
  849.     display, so can cancel and update event pending for the window.
  850. */
  851.  
  852.     CalcEditRect (&r);
  853.     dispTE = TENew (&r, &r);
  854.  
  855. # ifndef    singleDisplay
  856.  
  857. /*
  858.     Get new information structure, attach to list of known display
  859.     windows.
  860. */
  861.     dInfo = New (DisplayInfo);
  862.     (**dInfo).dNext = dwList;
  863.     dwList = dInfo;
  864.     (**dInfo).dWind = dispWind;
  865.     (**dInfo).dScroll = dispScroll;
  866.     (**dInfo).dTE = dispTE;
  867.     
  868. # endif
  869.  
  870.     SetDWindowNotify (dispWind, d_activate);
  871.     SetDWindowFlush (dispWind, d_maxText, d_flushAmt);
  872.     SetDWindowStyle (dispWind, d_font, d_size, d_wrap, d_just);
  873.  
  874. /*
  875.     Make window current display output window
  876. */
  877.  
  878.     SetDWindow (dispWind);
  879.     SetPort (savePort);
  880. }
  881.  
  882.  
  883. /*
  884.     Create and initialize a display window and the associated data
  885.     structures, and return the window pointer.  Install window in
  886.     list of display windows.  In single-window mode, disallow
  887.     creation of a new window if one already exists.
  888.  
  889.     The parameters are similar to those for NewWindow.  See Inside
  890.     Macintosh.
  891. */
  892.  
  893. WindowPtr NewDWindow (bounds, title, visible, behind, goAway, refCon)
  894. Rect        *bounds;
  895. StringPtr    title;
  896. Boolean        visible;
  897. WindowPtr    behind;
  898. Boolean        goAway;
  899. long        refCon;
  900. {
  901.  
  902. # ifdef    singleDisplay
  903.  
  904.     if (dispWind != nil)
  905.         return (nil);
  906.  
  907. # endif
  908.  
  909.     dispWind = NewWindow (nil, bounds, title, visible,
  910.                             documentProc, behind, goAway, refCon);
  911.     SetupDWindow ();
  912.     return (dispWind);
  913. }
  914.  
  915.  
  916. /*
  917.     Create and initialize a display window (using a resource) and
  918.     the associated data structures, and return the window pointer.
  919.     Install window in list of display windows.  In single-window
  920.     mode, disallow creation of a new window if one already exists.
  921.  
  922.     The parameters are similar to those for GetNewWindow.  See Inside
  923.     Macintosh.
  924. */
  925.  
  926. WindowPtr GetNewDWindow (resourceNum, behind)
  927. int            resourceNum;
  928. WindowPtr    behind;
  929. {
  930.  
  931. # ifdef    singleDisplay
  932.  
  933.     if (dispWind != nil)
  934.         return (nil);
  935.  
  936. # endif
  937.  
  938.     dispWind = GetNewWindow (resourceNum, nil, behind);
  939.     SetupDWindow ();
  940.     return (dispWind);
  941. }
  942.  
  943.  
  944.  
  945.  
  946. /* ------------------------------------------------------------ */
  947. /*                        Output Routines                            */
  948. /* ------------------------------------------------------------ */
  949.  
  950.  
  951. /*
  952.     Write text to display area if output is on (curDispWind != nil).
  953.     DisplayText is the fundamental output routine.  All other
  954.     output calls map (eventually) to it.
  955.  
  956.     First check whether the insertion will cause overflow and flush
  957.     out some stuff if so.  Insert new text at the end, then test
  958.     whether lines must be scrolled to get the new stuff to show up.
  959.     If yes, then do the scroll.  Set values of scroll bar properly
  960.     and highlight as appropriate.
  961.  
  962.     The current port is preserved.  Since all output calls end up
  963.     here, it's the only output routine that has to save the port
  964.     and check whether output is on.
  965. */
  966.  
  967. DisplayText (theText, len)
  968. Ptr        theText;
  969. long    len;
  970. {
  971. register int    nLines;            /* number of lines in TERec */
  972. register int    dispLines;        /* number of lines displayable in window */
  973. register int    topLines;        /* number of lines currently scrolled off top */
  974. register int    scrollLines;    /* number of lines to scroll up */
  975. register int    lHeight;
  976. Rect            r;
  977. GrafPtr            savePort;
  978. register TEHandle    dTE;
  979.  
  980.     if (curDispWind == nil)
  981.         return;
  982.  
  983.     GetPort (&savePort);
  984.     SetPort (curDispWind);
  985.     SyncGlobals (curDispWind);
  986.     dTE = dispTE;
  987.  
  988.     if ((**dTE).teLength + len > dMaxText)    /* check overflow */
  989.     {
  990.         FlushDWindow (dispWind, dFlushAmt);
  991.         DisplayString ("\p\r(autoflush occurred)\r");
  992.     }
  993.  
  994.     lHeight = (**dTE).lineHeight;
  995.     TESetSelect (32767L, 32767L, dTE);    /* set to insert at end */
  996.     TEInsert (theText, len, dTE);
  997.     r = (**dTE).viewRect;
  998.     nLines = (**dTE).nLines;
  999.     dispLines = (r.bottom - r.top) / lHeight;
  1000.     topLines = LinesOffTop ();
  1001.     scrollLines = nLines - (topLines + dispLines);
  1002.     if (scrollLines > 0) /* must scroll up */
  1003.         TEScroll (0, -lHeight * scrollLines, dTE); /* scroll up */
  1004.     topLines = nLines - dispLines;
  1005.     if (topLines >= 0 && GetCtlMax (dispScroll) != topLines)
  1006.     {
  1007.         SetCtlMax (dispScroll, topLines);
  1008.         SetCtlValue (dispScroll, topLines);
  1009.     }
  1010.     HiliteScroll ();
  1011.     SetPort (savePort);
  1012. }
  1013.  
  1014.  
  1015. /*
  1016.     Derived output routines:
  1017.  
  1018.     DisplayString    Write (Pascal) string
  1019.  
  1020.     DisplayLong        Write value of long integer
  1021.     DisplayInt        Write value of integer
  1022.     DisplayChar        Write character
  1023.  
  1024.     DisplayHexLong    Write value of long integer in hex (8 digits)
  1025.     DisplayHexInt    Write value of integer in hex (4 digits)
  1026.     DisplayHexChar    Write value of character in hex (2 digit)
  1027.  
  1028.     DisplayBoolean    Write boolean value
  1029.     DisplayLn        Write carriage return
  1030. */
  1031.  
  1032. DisplayString (theStr)
  1033. StringPtr    theStr;
  1034. {
  1035.     DisplayText (theStr+1, (long) theStr[0]);
  1036. }
  1037.  
  1038.  
  1039. DisplayLong (l)
  1040. long        l;
  1041. {
  1042. Str255        s;
  1043.  
  1044.     NumToString (l, s);
  1045.     DisplayString (s);
  1046. }
  1047.  
  1048.  
  1049. DisplayInt (i)
  1050. int        i;
  1051. {
  1052.     DisplayLong ((long) i);
  1053. }
  1054.  
  1055.  
  1056. DisplayChar (c)
  1057. char    c;
  1058. {
  1059.     DisplayText (&c, 1L);
  1060. }
  1061.  
  1062.  
  1063. DisplayLn ()
  1064. {
  1065.     DisplayChar ('\r');
  1066. }
  1067.  
  1068.  
  1069. DisplayBoolean (b)
  1070. Boolean    b;
  1071. {
  1072.     DisplayString (b ? "\ptrue" : "\pfalse");
  1073. }
  1074.  
  1075.  
  1076. static HexByte (value)    /* should be 0..15 */
  1077. int        value;
  1078. {
  1079.     DisplayChar ((char) (value + (value < 10 ? '0' : 'a' - 10)));
  1080. }
  1081.  
  1082.  
  1083. DisplayHexChar (c)
  1084. char    c;
  1085. {
  1086.     HexByte ((int) (c >> 4) & 0x0f);
  1087.     HexByte ((int) c & 0x0f);
  1088. }
  1089.  
  1090.  
  1091. DisplayHexInt (i)
  1092. int        i;
  1093. {
  1094.     DisplayHexChar ((char) ((i >> 8) & 0xff));
  1095.     DisplayHexChar ((char) (i & 0xff));
  1096. }
  1097.  
  1098.  
  1099. DisplayHexLong (l)
  1100. long    l;
  1101. {
  1102.     DisplayHexInt ((int) (l >> 16) & 0xffff);
  1103.     DisplayHexInt ((int) l & 0xffff);
  1104. }
  1105.